﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Reflection;
using System.Web;
using System.Collections;
using System.Data;

namespace Components
{
    public class CommonUtil
    {
        private static CommonUtil _instance = null;

        public static CommonUtil GetInstance
        {
            get
            {
                if (_instance == null)
                    return new CommonUtil();
                return _instance;
            }
        }

        /// <summary>
        /// 将对象source的属性拷贝到target中
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="overlaytargetIfNull">当对象target中有值的情况下是否覆盖</param>
        /// <param name="overlaysourceIfNull">当对象source中有值的情况下是否覆盖</param>
        public void CopyProperties(object source, object target, bool overlaytargetIfNull, bool overlaysourceIfNull)
        {
            PropertyInfo[] fromFields = source.GetType().GetProperties();
            PropertyInfo[] toFields = target.GetType().GetProperties();

            PropertyInfo fromField = null;
            PropertyInfo toField = null;
            int formLen = fromFields.Length;
            int toLen = toFields.Length;
            object sourceValue = null;
            for (int f = 0; f < formLen; f++)
            {
                fromField = (PropertyInfo)fromFields[f];
                for (int t = 0; t < toLen; t++)
                {
                    toField = (PropertyInfo)toFields[t];
                    if (fromField.Name != toField.Name) continue;
                    if (!toField.CanWrite) continue;
                    sourceValue = fromField.GetValue(source, null);
                    if (!overlaysourceIfNull && (null == sourceValue || "" == sourceValue.ToString())) continue; //不覆盖值
                    if (!overlaytargetIfNull && null != toField.GetValue(target, null)) continue; //不覆盖值
                    toField.SetValue(target, fromField.GetValue(source, null), null);
                    break;
                }
            }
        }

        /// <summary>
        /// 将HashTable中的键拷贝到target对象的对应的属性中，不区分大小写哦
        /// </summary>
        /// <param name="hs"></param>
        /// <param name="target"></param>
        public void CopyProperties(Hashtable hs, object target)
        {
            if (null == hs || null == target) return;

            PropertyInfo[] toFields = target.GetType().GetProperties();
            string pname = "";
            object v = null;
            foreach (PropertyInfo info in toFields)
            {
                if (!info.CanWrite) continue;
                pname = info.Name.ToLower();

                if (!hs.ContainsKey(pname)) continue;
                v = hs[pname];

                Type propertyType = info.PropertyType;

                if (propertyType == typeof(bool?) || propertyType == typeof(bool))
                {
                    v = Validation.ToBool(v);
                }

                if (propertyType == typeof(decimal?) || propertyType == typeof(decimal)
                    || propertyType == typeof(double?) || propertyType == typeof(double))
                {
                    var value = Validation.ToString(v);
                    if (value.IndexOf("%", System.StringComparison.Ordinal) > -1)
                    {
                        v = Validation.PercentToNumber(value);
                    }
                }

                try
                {
                    AddValue(info, Validation.ToString(v), target);
                }
                catch
                {
                    LogHelper.Entity.Out(string.Format("在给{0}的{1}赋{2}失败。", target.GetType().FullName, info.Name, v));
                    throw;
                }
            }
        }

        /// <summary>
        /// 向属性中添加对应类型的值
        /// </summary>
        /// <param name="info">属性对象</param>
        /// <param name="Value">值</param>
        /// <param name="obj">属性所属对象</param>
        /// <param name="hasKey">Request对象中是否有该属性</param>
        public void AddValue(PropertyInfo info, String value, Object obj)
        {
            if (string.IsNullOrEmpty(value)) //如果是空
            {
                info.SetValue(obj, null, null);
                return;
            }
            if (info.PropertyType == typeof(String))
            {
                info.SetValue(obj, value, null);
            }
            else if (info.PropertyType == typeof(int?) || info.PropertyType == typeof(int))
            {
                info.SetValue(obj, int.Parse(value), null);
            }
            else if (info.PropertyType == typeof(DateTime?) || info.PropertyType == typeof(DateTime))
            {
                info.SetValue(obj, DateTime.Parse(value), null);
            }
            else if (info.PropertyType == typeof(Decimal?) || info.PropertyType == typeof(Decimal))
            {
                info.SetValue(obj, Decimal.Parse(value), null);
            }
            else if (info.PropertyType == typeof(Double?) || info.PropertyType == typeof(Double))
            {
                info.SetValue(obj, Double.Parse(value), null);
            }
            else if (info.PropertyType == typeof(float?) || info.PropertyType == typeof(float))
            {
                info.SetValue(obj, float.Parse(value), null);
            }
            else if (info.PropertyType == typeof(bool?) || info.PropertyType == typeof(bool))
            {
                info.SetValue(obj, (value != "0"), null);
            }
            else if (info.PropertyType == typeof(Guid?) || info.PropertyType == typeof(Guid))
            {
                if (value != null)
                    info.SetValue(obj, new Guid(value), null);
            }

        }

        /// <summary>
        /// 将Dr中的值Copy到o中
        /// </summary>
        /// <param name="o"></param>
        /// <param name="dr"></param>
        public void CopyProperties(object target, DataRow dr)
        {
            if (null == dr || null == target) return;

            PropertyInfo[] toFields = target.GetType().GetProperties();
            string pname = "";
            object v = null;
            DataColumnCollection dcc = dr.Table.Columns;
            foreach (PropertyInfo info in toFields)
            {
                if (!info.CanWrite) continue;
                pname = info.Name.ToLower();

                if (!dcc.Contains(pname)) continue;
                v = dr[pname];

                if (v is DBNull)
                    v = null;

                if (info.PropertyType == typeof(bool?) || info.PropertyType == typeof(bool))
                {
                    v = Validation.ToBool(v);
                }
                else if (info.PropertyType == typeof(double?) || info.PropertyType == typeof(double))
                {
                    v = Validation.ToDouble(v);
                }
                else if (info.PropertyType == typeof(int?) || info.PropertyType == typeof(int))
                {
                    v = Validation.ToInt(v);
                }
                else if (info.PropertyType == typeof(DateTime?) || info.PropertyType == typeof(DateTime))
                {
                    if (v != null)
                        v = Validation.ToDate(v);
                }

                info.SetValue(target, v, null);
            }
        }

        /// <summary>
        /// 将KeyValuePair转换成Hashtable
        /// </summary>
        /// <param name="ks"></param>
        /// <returns></returns>
        public Hashtable ConvertToHashtable(KeyValuePair<string, object>[] ks)
        {
            if (ks == null || ks.Length == 0) return null;

            Hashtable hs = new Hashtable();
            foreach (KeyValuePair<string, object> s in ks)
            {
                hs[s.Key] = s.Value;
            }

            return hs;
        }

        #region 文件操作
        /// <summary>
        /// 序列化对象，返回字节数组(序列化类前加[Serializable])
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public byte[] SerializerToObject(object obj)
        {
            byte[] byteArray = null;
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();

                //关键语句，这句话完成了对象到数据流的转换
                binaryFormatter.Serialize(ms, obj);

                //把指针从新定格为最初的状态
                ms.Position = 0;
                byteArray = new Byte[ms.Length];

                ms.Read(byteArray, 0, (int)ms.Length);
                ms.Close();
            }
            return byteArray;
        }


        /// <summary>
        /// 将一个数组反序列化成对象
        /// </summary>
        /// <param name="by"></param>
        /// <returns></returns>
        public object DeserializeToObject(byte[] objArr)
        {
            object obj;
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                ms.Write(objArr, 0, objArr.Length);

                ms.Position = 0;

                //关键语句，这句话完成了数据流到对象的转换
                obj = binaryFormatter.Deserialize(ms);
                ms.Close();
            }
            return obj;
        }

        /// <summary>
        /// 将字节数组的内容存到文件中 (如果存在，添加在其内容之后)
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="filecontent"></param>
        public void SaveToFile(string filename, string filecontent)
        {
            _saveToFile(filename, filecontent, false);
        }

        /// <summary>
        /// 将字节数组的内容存到文件中 (如果存在，覆盖)
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="filecontent"></param>
        public void SaveToFileOverride(string filename, string filecontent)
        {
            _saveToFile(filename, filecontent, true);
        }

        private void _saveToFile(string filename, string filecontent, bool overr)
        {
            FileStream stream = null;

            if (!File.Exists(filename))
                stream = File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write);
            else
                stream = File.Open(filename, overr ? FileMode.Create : FileMode.Append, FileAccess.Write);

            StreamWriter writer = new StreamWriter(stream, Encoding.Default);

            writer.Write(filecontent);
            writer.Flush();
            writer.Close();
            stream.Close();
        }

        /// <summary>
        /// 从文件中读出保存的信息，放入字节数组中
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public string LoadFromFile(string filename)
        {
            if (!File.Exists(filename)) return "";

            FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read);

            StreamReader reader = new StreamReader(stream, Encoding.Default);

            string content = reader.ReadToEnd();

            reader.Close();
            stream.Close();

            return content;
        }
        #endregion

        #region 反射相关
        /// <summary>
        /// 通过反射调用方法
        /// </summary>
        /// <param name="ClassName"></param>
        /// <param name="MethodName"></param>
        /// <param name="objArry"></param>
        /// <returns></returns>
        public object GetInfoByReflect(String assName, String className, String methodName, object[] objArry)
        {
            Object obj = null;
            Object dt = null;
            try
            {
                //装载程序集
                Assembly assembly = Assembly.Load(assName);

                //通过字符串，创建对象
                obj = assembly.CreateInstance(String.Format("{0}.{1}", assName, className));

                //得到对象的类型信息
                Type type = obj.GetType();

                Object objBLL = type.InvokeMember(null, //得到该对象的实例
                        BindingFlags.DeclaredOnly |
                        BindingFlags.Public | BindingFlags.NonPublic |
                        BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null);

                //调用该类的业务逻辑层的非静态方法GetList得到数据
                dt = type.InvokeMember(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, objBLL, objArry);
            }
            catch (Exception ex)
            {
                LogHelper.Entity.Out(string.Format("反射{0}类的{1}方法出错=>" + ex.InnerException.StackTrace, className, methodName));
                if (ex.InnerException != null && ex.InnerException is StnException)
                    throw ex.InnerException;

                throw new Exception("录入的信息不符合规范");
            }
            return dt;
        }

        /// <summary>
        /// 克隆
        /// </summary>
        /// <returns></returns>
        public Object Clone(object o)
        {
            MemoryStream ms = new MemoryStream();

            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, o);
            ms.Seek(0, 0);
            object value = bf.Deserialize(ms);

            ms.Close();

            return value;

        }
        #endregion
    }
}
